# Copyright (C) 2007 Insecure.Com LLC.
#
# Authors: Guilherme Polo <ggpolo@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 
# USA

import gtk
import cairo
import pango
from gettext import gettext as _

from Base import too_dark
from Base import cairoc_to_gdkc


# ToDo: Make it resizable

class TL_EventPopup(gtk.Window):
    """
    Popup window with an event related to some date.
    """

    def __init__(self, daddy, x_ini=0, y_ini=0, color=(0.53, 0.52, 0.43), 
                 text='',  title="(23:33) Thursday, March's 15 - 2007",
                 zoom_level=0, data_activate=0, gradient=True):
        """
        Params:
        
        daddy            - TimeLine instance
        x_ini, y_ini     - coords where the popup will popup (or not).
        color            - a tuple containing rgb values from 0 to 1.
        text             - text to display.
        title            - title to be displayed on top.
        zoom_level       - TimeLine current zoom level when this get called.
        data_activate    - A number that represents something for TimeLine.        
        gradient         - Draw gradient on top, or not.
        """
        
        gtk.Window.__init__(self, gtk.WINDOW_POPUP)
        
        self.coord = (x_ini, y_ini)
        self.zl = zoom_level
        self.zd = data_activate
        self.daddy = daddy
        self.rgb_color = color[:3]
        self.gradient = gradient
        
        g_color = cairoc_to_gdkc(color[0], color[1], color[2])
        self.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(*g_color))

        # title
        if too_dark(self.rgb_color):
            c = "#eeeeec"
        else:
            c = "#000"
        
        self.titlepop = gtk.Label()
        self.titlepop.set_markup("<span foreground=\"%s\"> %s%s\
</span>" % (c, title, ' '*5))
        self.btnclose = gtk.Button(label="x")
        self.btnzoom = gtk.Button(label="z")
        #self.btnclose.set_size_request(-1, 18)
        #self.btnzoom.set_size_request(-1, 18)
        
        # text view
        self.eb = gtk.EventBox()
        self.expander = gtk.Expander(_("Details"))
        label = gtk.Label(_("Details can be shown or hidden."))
        self.expander.add(label)
        self.eb.add(self.expander)
        
        self.tview = gtk.TextView()
        tvbuffer = self.tview.get_buffer()
        iter = tvbuffer.get_iter_at_offset(0)
        tvbuffer.insert(iter, "%s\n\n" % text) # insert text on textview
        anchor = tvbuffer.create_child_anchor(iter)
        self.tview.add_child_at_anchor(self.eb, anchor) # insert sample widget
        
        # scrolledwindow to hold self.tview
        self.textsw = gtk.ScrolledWindow() 
        self.textsw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        
        # tooltips
        self.ttips = gtk.Tooltips()
        self.ttips.set_tip(self.btnclose, _("Close window"))
        self.ttips.set_tip(self.btnzoom, _("Zoom in")) 
        
        
        if self.zl == 3 or not self.daddy: # already at max zoom level
            self.btnzoom.set_sensitive(False)
        
        
        self.__do_layout()
        self.__conn_evts()
        
        self.set_events(gtk.gdk.EXPOSURE_MASK |
                        gtk.gdk.LEAVE_NOTIFY_MASK |
                        gtk.gdk.BUTTON_PRESS_MASK |
                        gtk.gdk.BUTTON_RELEASE_MASK |
                        gtk.gdk.POINTER_MOTION_MASK |
                        gtk.gdk.POINTER_MOTION_HINT_MASK)        
    
        
    def get_gradient(self):
        """
        Returns True if gradient will be used on draw.
        """
        return self.__gradient
    
    
    def set_gradient(self, gradient):
        """
        Sets gradient to True/False on draw
        """
        self.__gradient = gradient
    
    
    def zoom_in(self, event):
        """
        Zoom one level if possible.
        """
        self.daddy.zoom = self.zl
        
        if self.zl == 0:
            self.daddy.month = self.zd + 1
        elif self.zl == 1:
            self.daddy.day = self.zd + 1
        elif self.zl == 2:
            self.daddy.hour = self.zd
            
        self.daddy.emit('date-change-notify')
        self.daddy.zoom_in()
        
        self.btnzoom.set_sensitive(False)

    
    def close(self, widget=None, event=None):
        """
        Closes this window.
        """    
        self.destroy()


    ##
    # Private methods follows.
    
    def __conn_evts(self):
        """
        Connect events.
        """
        self.btnzoom.connect('clicked', self.zoom_in)
        self.btnclose.connect('clicked', self.close)
        
        self.connect('realize', self.__realize)
        self.connect('expose-event', self.__expose)
        self.connect('size-request', self.__size_request)
        self.connect('button-release-event', self.__mouse_release)
        self.connect('button-press-event', self.__mouse_press)
        self.connect('motion-notify-event', self.__mouse_motion)

    
    def __do_layout(self):
        """
        Layout widgets
        """
        vbox = gtk.VBox()
        vbox.set_spacing(3)
        vbox.set_border_width(1)
        vboxtv = gtk.VBox()
        vboxtv.set_border_width(3)
        bar = gtk.HBox()
        bar.set_spacing(3)
        
        # bar packing
        bar.pack_start(self.titlepop, False, False, 0)
        bar.pack_end(self.btnclose, False, False, 3)        
        bar.pack_end(self.btnzoom, False, False, 0)
        
        # vboxtv packing
        self.textsw.add(self.tview)
        vboxtv.pack_start(self.textsw, True, True, 0)
        
        # main vbox packing
        vbox.pack_start(bar, False, False, 0)
        vbox.pack_start(vboxtv, True, True, 1)
        
        self.add(vbox)
    
    
    def __realize(self, event):
        """
        This is being used for setting "especial" cursor for eventbox, 
        for getting some button size, and for window positionment.
        """
        self.eb.realize()
        self.eb.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))
        
        btnalloc = self.btnclose.get_allocation()
        self.__btn_height = btnalloc[3]
        
        self.__adjust_win(*self.coord)
    

    def __adjust_win(self, x, y):
        """
        Adjusts where the window will popup.
        """
        self.move(int(x), int(y))
        
        return None
    
        """
        alloc = self.get_allocation()
        tw, th = alloc[2], alloc[3]
        mw, mh = gtk.gdk.get_default_root_window().get_size()
        
        if tw+x > mw:
            diff = (tw+x) - mw
            x -= diff
        
        if th+y > mh:
            diff = (th+y) - mh
            y -= diff
        
        self.move(x, y)
        """


    def __mouse_press(self, widget, event):
        """
        Mouse button pressed.
        """
        x, y = self.get_pointer()
        orig_x, orig_y = event.window.get_root_origin()
        self.delta = ((x, y))
        event.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.FLEUR))
        
        return True
    
    
    def __mouse_release(self, widget, event):
        """
        Mouse button released.
        """
        event.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))
     
        return True


    def __mouse_motion(self, widget, event):
        """
        Mouse pointer moving.
        """
        try:
            self.delta
        except AttributeError:
            return
        
        x, y, state = event.window.get_pointer()
        if state & gtk.gdk.BUTTON1_MASK:
            orig_x, orig_y = event.window.get_root_origin()
            self.move(x + orig_x - self.delta[0], y + orig_y - self.delta[1])
        
        return True
    
    
    def __expose(self, widget, event):
        """
        Draws a gradient on top or not.
        """
        if not self.gradient:
            return
        
        cr = self.window.cairo_create()
        
        cr.rectangle(0, 0, self.allocation[2], self.__btn_height + 2)
        
        pat = cairo.LinearGradient(0, 0, 0, self.__btn_height + 2)
        pat.add_color_stop_rgba(0, 1, 1, 1, 0.5)
        pat.add_color_stop_rgba(0.8, self.rgb_color[0], self.rgb_color[1],
                                self.rgb_color[2], 1)          
        cr.set_source(pat)
        
        cr.fill()
    

    def __size_request(self, widget, event):
        """
        Sets a good size for the window.
        """
        w, _ = self.titlepop.get_layout().get_size()
        w = (w / pango.SCALE) + 51
        if w < 201:
            w = 201
        
        self.set_size_request(w, int(w / 1.618))


    # Properties
    gradient = (get_gradient, set_gradient)        
    
    
if __name__ == "__main__":
        from this import s
        d = {}
        for c in (65, 97):
            for i in range(26):  d[chr(i+c)] = chr((i+13) % 26 + c)
        
        sample = TL_EventPopup(None, text= "".join([d.get(c, c) for c in s]))
        sample.connect('destroy', lambda w: gtk.main_quit())
        sample.show_all()
        gtk.main()
    